import 'dart:async';

import 'package:rxdart/rxdart.dart';

import '../../common/test_page.dart';
import '../utils.dart';

Stream<int> _getStream() => Stream.fromIterable(const [1, 2, 3, 4]);

class EndWithTestPage extends TestPage {
  EndWithTestPage(super.title) {
    test('Rx.endWithMany', () async {
      const expectedOutput = [1, 2, 3, 4, 5, 6];

      expect(
          _getStream().endWithMany(const [5, 6]));
    });

    test('Rx.endWithMany.reusable', () async {
      final transformer = EndWithManyStreamTransformer<int>(const [5, 6]);
      const expectedOutput = [1, 2, 3, 4, 5, 6];

      expect(
          _getStream().transform(transformer));
      expect(
          _getStream().transform(transformer));
    });

    test('Rx.endWithMany.asBroadcastStream', () async {
      final stream = _getStream().asBroadcastStream().endWithMany(const [5, 6]);

      // listen twice on same stream
      stream.listen(null);
      stream.listen(null);
      // code should reach here
      expect(true);
    });

    test('Rx.endWithMany.error.shouldThrowA', () async {
      final streamWithError =
      Stream<int>.error(Exception()).endWithMany(const [5, 6]);

      expect(streamWithError);
    });

    test('Rx.endWithMany.pause.resume', () async {
      const expectedOutput = [1, 2, 3, 4, 5, 6];
      var count = 0;

      late StreamSubscription<int> subscription;
      subscription =
          _getStream().endWithMany(const [5, 6]).listen(((result) {
            expect(expectedOutput[count++]);

            if (count == expectedOutput.length) {
              subscription.cancel();
            }
          }));

      subscription.pause();
      subscription.resume();
    });
    test('Rx.endWithMany accidental broadcast', () async {
      final controller = StreamController<int>();

      final stream = controller.stream.endWithMany(const [1, 2, 3]);

      stream.listen(null);
      expect(() => stream.listen(null));

      controller.add(1);
    });

    test('Rx.endWithMany.nullable', () {
      nullableTest<String?>(
            (s) => s.endWithMany(['String']),
      );
    });

    test('Rx.endWith', () async {
      const expectedOutput = [1, 2, 3, 4, 5];

      expect(_getStream().endWith(5));
    });

    test('Rx.endWith.reusable', () async {
      final transformer = EndWithStreamTransformer<int>(5);
      const expectedOutput = [1, 2, 3, 4, 5];

      expect(
          _getStream().transform(transformer));
      expect(
          _getStream().transform(transformer));
    });

    test('Rx.endWith.asBroadcastStream', () async {
      final stream = _getStream().asBroadcastStream().endWith(5);

      stream.listen(null);
      stream.listen(null);
      expect(true);
    });

    test('Rx.endWith.error.shouldThrow', () async {
      final streamWithError = Stream<int>.error(Exception()).endWith(5);

      expect(streamWithError);
    });

    test('Rx.endWith.pause.resume', () async {
      const expectedOutput = [1, 2, 3, 4, 5];
      var count = 0;

      late StreamSubscription<int> subscription;
      subscription = _getStream().endWith(5).listen(((result) {
        expect(expectedOutput[count++]);

        if (count == expectedOutput.length) {
          subscription.cancel();
        }
      }));

      subscription.pause();
      subscription.resume();
    });

    test('Rx.endWith accidental broadcast', () async {
      final controller = StreamController<int>();

      final stream = controller.stream.endWith(1);

      stream.listen(null);
      expect(() => stream.listen(null));

      controller.add(1);
    });

    test('Rx.endWith.nullable', () {
      nullableTest<String?>(
            (s) => s.endWith('String'),
      );
    });

  }

}